#include "CmdGit.h"
#include "FileDisplay.h"
#include "GitInfo.h"
#include "Init.h"
#include "Tool.h"
#include "MenuWin.h"


#define LAB1 "./lab1"
#define LAB2 "./lab2"
#define LAB3 "./lab3"
#define LAB4 "./lab4"
#define SHELL1 "./lab1/lab1.sh"
#define SHELL2 "./lab2/lab2.sh"
#define SHELL3 "./lab3/lab3.sh"
#define SHELL4 "./lab4/lab4.sh"
#define CAST1 "./lab1/lab1.cast"
#define CAST2 "./lab2/lab2.cast"
#define CAST3 "./lab3/lab3.cast"
#define CAST4 "./lab4/lab4.cast"
#define DEMAND1 "./lab1/lab1.txt"
#define DEMAND2 "./lab2/lab2.txt"
#define DEMAND3 "./lab3/lab3.txt"
#define DEMAND4 "./lab4/lab4.txt"

#define CHECK_PATH "/tmp/shellcheck_results.txt"

//  welcome
void welcome()
{
    const char *WELCOME_TEXT =
        R"(
__        _______ _     ____ ___  __  __ _____ 
\ \      / / ____| |   / ___/ _ \|  \/  | ____|
 \ \ /\ / /|  _| | |  | |  | | | | |\/| |  _|  
  \ V  V / | |___| |__| |__| |_| | |  | | |___ 
   \_/\_/  |_____|_____\____\___/|_|  |_|_____|
)";

    int rows, cols;

    getmaxyx(stdscr, rows, cols);
    WINDOW *start_win = newwin(0, 0, 0, 0);
    box(start_win, 0, 0);

    int line_count = 0;
    int max_width = 0;
    size_t start = 0, end;
    std::string text = WELCOME_TEXT;

    // 计算最大宽度和行数
    while ((end = text.find('\n', start)) != std::string::npos)
    {
        max_width = std::max(max_width, static_cast<int>(end - start));
        line_count++;
        start = end + 1;
    }

    int x = (cols - max_width) / 2;
    int y = (rows - line_count) / 2;

    // 逐行输出居中文本
    start = 0;
    int current_line = 0;
    while ((end = text.find('\n', start)) != std::string::npos)
    {
        mvwprintw(start_win, (y + current_line), x, text.substr(start, end - start).c_str());
        start = end + 1;
        current_line++;
    }
    wrefresh(start_win);
    napms(2000);
    delwin(start_win);
    clear();
    refresh();
}

// 选择实验
int lab_choice()
{
    std::vector<std::string> dir = {
        "lab1",
        "lab2",
        "lab3",
        "lab4"};
    WINDOW *lab_win = newwin(8, 25, (LINES - 8) / 2, (COLS - 25) / 2);
    box(lab_win, 0, 0);
    mvwprintw(lab_win, 0, 1, "lab");
    wrefresh(lab_win);
    auto *lab_menu = new MenuWin(lab_win, dir);
    int choice = lab_menu->run();
    delete lab_menu;
    delwin(lab_win);
    clear();
    refresh();
    return choice;
}

// 主页面
void main_page(const nlohmann::json &student, int lab)
{
    std::string lab_dir;
    std::string shell_file;
    std::string cast_file;
    std::string demand_file;
    std::string git_url = student["git"];
    std::string editor = student["editor"];
    const std::vector<std::string> dir = {
        "lab1",
        "lab2",
        "lab3",
        "lab4"};
    std::vector<std::string> exit_info = {"exit_and_push", "exit"};
    auto choice = [&](int n)
    {
        switch (n)
        {
        case 0:
            lab_dir = LAB1;
            shell_file = SHELL1;
            cast_file = CAST1;
            demand_file = DEMAND1;
            break;
        case 1:
            lab_dir = LAB2;
            shell_file = SHELL2;
            cast_file = CAST2;
            demand_file = DEMAND2;
            break;
        case 2:
            lab_dir = LAB3;
            shell_file = SHELL3;
            cast_file = CAST3;
            demand_file = DEMAND3;
            break;
        case 3:
            lab_dir = LAB4;
            shell_file = SHELL4;
            cast_file = CAST4;
            demand_file = DEMAND4;
            break;
        }
    };

    choice(lab);

    // 创建主窗口
    WINDOW *main_win = newwin(LINES, COLS, 0, 0);
    int height, width;
    getmaxyx(main_win, height, width);
    // 创建主窗口的三个子窗口
    // 学生shell窗口
    WINDOW *shell_win = derwin(main_win, height - 4, width / 2 - 1, 1, 1);
    box(shell_win, 0, 0);
    mvwprintw(shell_win, 0, 1, "Shell");
    // wrefresh(shell_win);
    //  要求窗口
    WINDOW *demand_win = derwin(main_win, height - 4, width / 2 - 1, 1, (width / 2 + 1));
    box(demand_win, 0, 0);
    mvwprintw(demand_win, 0, 1, "Demand");
    // wrefresh(demand_win);
    //  操作提示窗口
    WINDOW *button_win = derwin(main_win, 3, width - 1, height - 3, 1);
    box(button_win, 0, 0);
    mvwprintw(button_win, 0, 1, "Button");
    mvwprintw(button_win, 1, 1, "s:start");
    mvwprintw(button_win, 1, 11, "g:git");
    mvwprintw(button_win, 1, 21, "c:check");
    mvwprintw(button_win, 1, 31, "l:choice lab");
    mvwprintw(button_win, 1, 51, "q:exit");
    // wrefresh(button_win);
    //  git窗口
    WINDOW *git_win = newwin(20, 60, (LINES - 20) / 2, (COLS - 60) / 2);
    box(git_win, 0, 0);
    // wrefresh(git_win);
    //  shellcheck窗口
    WINDOW *check_win = newwin(LINES - 4, 60, 1, (COLS - 60) / 2);
    box(check_win, 0, 0);
    mvwprintw(check_win, 0, 1, "ShellCheck Results");
    // 实验选择窗口
    WINDOW *lab_win = newwin(8, 25, (LINES - 8) / 2, (COLS - 25) / 2);
    box(lab_win, 0, 0);
    mvwprintw(lab_win, 0, 1, "lab");
    // 退出选项窗口
    WINDOW *exit_win = newwin(8, 25, (LINES - 8) / 2, (COLS - 25) / 2); // 退出窗口
    box(exit_win, 0, 0);
    mvwprintw(exit_win, 0, 1, "Exit");
    refresh();

    // 创建面板
    PANEL *main_panel = new_panel(main_win);
    PANEL *git_panel = new_panel(git_win);
    PANEL *check_panel = new_panel(check_win);
    PANEL *lab_panel = new_panel(lab_win);
    PANEL *exit_panel = new_panel(exit_win);
    top_panel(main_panel);
    update_panels();
    doupdate();

    // 创建主窗口显示和操作对象
    FileDisplay *shell_display = new FileDisplay(shell_win, shell_file);
    FileDisplay *demand_display = new FileDisplay(demand_win, demand_file);
    // shellcheck对象
    FileDisplay *check_display = new FileDisplay(check_win, CHECK_PATH);
    // git对象
    GitInfo *git = new GitInfo(git_win, lab_dir);
    // 实验选择对象
    MenuWin *lab_choice = new MenuWin(lab_win, dir);
    // 退出选择对象
    MenuWin *lab_exit = new MenuWin(exit_win, exit_info);

    shell_display->refresh_display();
    demand_display->refresh_display();

    int ch;
    curs_set(0);
    bool run = true;
    while (run)
    {
        ch = getch();
        switch (ch)
        {
        case KEY_DOWN:
        {
            shell_display->handle_input(ch);
            demand_display->handle_input(ch);
            break;
        }

        case KEY_UP:
        {
            shell_display->handle_input(ch);
            demand_display->handle_input(ch);
            break;
        }

        case 'l':
        {
            top_panel(lab_panel);
            update_panels();
            doupdate();
            int n = lab_choice->run();
            if (n == -1)
            {
                top_panel(main_panel);
                update_panels();
                doupdate();
            }
            else
            {
                lab = n;
                choice(lab);
                shell_display->change_file(shell_file);
                shell_display->run();
                demand_display->change_file(demand_file);
                demand_display->run();
                git->reinitialize(lab_dir);
                top_panel(main_panel);
                update_panels();
                doupdate();
            }
            break;
        }

        case 'c':
        {
            bool run1 = true;
            top_panel(check_panel);
            update_panels();
            doupdate();
            use_shellcheck(shell_file);
            check_display->reload_file();
            while (run1)
            {
                int ch = wgetch(check_win);
                if (ch == 'q')
                {
                    run1 = false;
                    break;
                }
                else
                {
                    check_display->handle_input(ch);
                    run1 = true;
                }
            }
            top_panel(main_panel);
            update_panels();
            doupdate();
            break;
        }

        case 'g':
        {
            top_panel(git_panel);
            update_panels();
            doupdate();
            git->reinitialize(lab_dir);
            std::string commit_message = git->run();
            if (!commit_message.empty())
            {
                git_add();
                git_commit(commit_message);
            }
            curs_set(0);
            top_panel(main_panel);
            update_panels();
            doupdate();
            break;
        }

        case 'q':
        {
            top_panel(exit_panel);
            update_panels();
            doupdate();
            int n = lab_exit->run();
            if (n == -1)
            {
                top_panel(main_panel);
                update_panels();
                doupdate();
            }
            else if (n == 0)
            {
                git_push();
                run = false;
            }
            else
            {
                run = false;
            }
            break;
        }

        case 's':
        {
            use_asciinema(editor, shell_file, cast_file);
            shell_display->reload_file();
            break;
        }

        default:
            break;
        }
    }

    // 清理释放
    delete shell_display;
    delete demand_display;
    delete check_display;
    delete git;
    delete lab_choice;
    delete lab_exit;

    del_panel(exit_panel);
    del_panel(lab_panel);
    del_panel(check_panel);
    del_panel(git_panel);
    del_panel(main_panel);

    delwin(exit_win);
    delwin(lab_win);
    delwin(check_win);
    delwin(git_win);
    delwin(button_win);
    delwin(demand_win);
    delwin(shell_win);
    delwin(main_win);
}

int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        std::cout << "Usage: " << argv[0] << " <dirname,your git repository>" << std::endl;
        return 1;
    }

    // 初始化ncurses
    initscr();
    start_color();
    use_default_colors();
    cbreak();
    noecho();
    keypad(stdscr, TRUE);
    curs_set(0);
    refresh();
    welcome();

    std::string work_dir = argv[1];

    if (!path_exists(work_dir))
    {
        std::cout << "Error: " << work_dir << " does not exist." << std::endl;
        return 1;
    }

    if (!is_directory(work_dir))
    {
        std::cout << "Error: " << work_dir << " is not a directory." << std::endl;
        return 1;
    }

    if (chdir(work_dir.c_str()) != 0)
    {
        std::cerr << "Error: Failed to change working directory to " << work_dir
                  << " (" << strerror(errno) << ")" << std::endl;
    }

    if (is_directory_empty("."))
    {
        user_init();
    }
    else
    {
        // 检查是否是git仓库
        if (!path_exists(".git") || !is_directory(".git"))
        {
            std::cout << "Error: " << work_dir << " is not a git repository." << std::endl;
            return 1;
        }
        git_pull();
    }
    // 读取student.json
    if (!path_exists("student.json"))
    {
        std::cout << "Error: student.json not found in " << work_dir << std::endl;
        return 1;
    }

    std::ifstream file("student.json");
    if (!file.is_open())
    {
        std::cout << "Error: Could not open student.json" << std::endl;
        return 1;
    }

    nlohmann::json student;
    file >> student;
    file.close();

    int lab = lab_choice();
    refresh();
    main_page(student, lab);

    clear();
    endwin();
    return 0;
}